05 - Wizualizacja danych

Podstawy przetwarzania danych

Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej

Ćwiczenie laboratoryjne 5: wizualizacja danych

Powrót do spisu treści ćwiczeń laboratoryjnych

Wprowadzenie

Matplotlib stanowi jedną z najpopularniejszych bibliotek służących do wizualnego prezentowania danych w Pythonie [1]. Dane mogą zostać przedstawione zarówno w sposób statyczny jak i dynamiczny. Do dyspozycji programisty pozostawiono wiele typów wykresów danych, w tym wykresy liniowe, wykresy słupkowe, wykresy kołowe, mapy ciepła, czy też wykresy 3D. W ramach niniejszych zajęć zapoznamy się tylko z wykresami liniowymi.

Struktura biblioteki Matplotlib przypomina tę, znaną ze środowisk MATLABa oraz Octave i w znacznym stopniu jest z nimi kompatybilna. Na szczególną uwagę zasługują nazwy metod, które mają swoje odpowiedniki w uprzednio wymienionych językach. Aby skorzystać z modułu, należy go uprzednio zainstalować. Służy do tego polecenie:

pip3 install matplotlib 

Dopiero gdy pakiet znajduje się na komputerze, możliwe jest jego zaimportowanie. W ramach zajęć wykorzystany zostanie moduł pyplot. Warto przy tej okazji utworzyć alias do niego (np. plot), aby skrócić ścieżkę odwołania do modułu

import matplotlib.pyplot as plot

Dla celów dydaktycznych, utworzony zostanie wykres funkcji f(x) = y + 10. W swojej najprostszej formie, kod będzie wyglądał następująco:

import numpy as np
import matplotlib.pyplot as plot

x = np.arange(1, 100, 2)
y = x + 10

plot.plot(x, y)
plot.show()

Wykorzystano tutaj bibliotekę numpy. Przy pomocy metody arange() wygenerowany został wektor zawierający wartości od 1 do 99 z krokiem 2. Wektor ten stanowi zbiór liczb dla osi X. W oparciu o niego, zdefiniowano także wektor Y w taki sposób, że każda z wartości została zwiększona o 10. Kolejny etap to wygenerowanie krzywej bazując na danych wejściowych. Metoda plot() pozwala na narysowanie zbioru punktów na wykresie oraz na zarządzanie nimi, w tym na zmianę ich wyglądu. Metoda show() pozwala z kolei na wyświetlenie dedykowanego okna wraz z wynikiem końcowym (wykresem). Należy podkreślić, że Matplotlib nie sprawdza poprawności rysowanych danych (np. poprawności funkcji matematycznej), a tylko nanosi punkty na płaszczyznę i kolejno łączy je ze sobą.


💥 Zadanie 1 💥

Sprawdź działanie powyższego kodu. Zmodyfikuj go tak, aby zakres wartości na osi X wynosił <0; 200>, a prosta została opisana równaniem y = 2x + 15. Nie używaj żadnych dodatkowych funkcji ani metod.


Zarządzanie wyglądem wykresu

Wykres w najprostszej swojej formie może okazać się bardzo nieczytelny. Oprócz braków w postaci opisów, legendy, czy odpowiednio sformatowanych zakresów osi, brak jest również linii i siatek pomocniczych. Dodanie powyższego sprawia, że grafika nie tylko wygląda lepiej, ale również niesiona przez nią informacja staje się łatwiejsza do zrozumienia.


💥 Zadanie 2 💥

Przygotuj wykres dla prostej o współrzędnych (0, 0) oraz (5, 5).


Wykres wyglądem bardzo przypomina ten, z rozdziału pierwszego, choć został zbudowany w oparciu tylko o 2 punkty. Na tym etapie zajmiemy się jego wizualną modyfikacją. Pierwszą z nich będzie zmiana koloru prostej. Do tego celu zmodyfikowane zostanie wywołanie metody plot(). Można tego dokonać na dwa sposoby - korzystając z etykiet argumentów lub ze skróconej formy zapisu. W przypadku etykiet, wymieniamy kolejne cechy wykresu, które mają podlegać modyfikacji. Załączony przykład obrazuje zmianę koloru linii (czerwona), rodzaju znacznika punktów (krzyżyk) oraz stylu linii (ciągła).

plot.plot(x, y, color='red', marker='x', linestyle='solid')

Alternatywnie, możliwe jest użycie skróconej formy zapisu. Trzy znaki (rx-) wskazują kolejno na kolor, typ użytego znacznika oraz na typ linii. W tym przypadku otrzymamy linię koloru czerwonego (r), gdzie zadane punkty zostaną zaznaczone krzyżykami (x), a sama linia będzie ciągła (-). Zapis ten jest tożsamy z użyciem etykiet argumentów.

plot.plot(x, y, 'rx-')

Pełna dokumentacja znajduje się na stronie twórców biblioteki [2].


💥 Zadanie 3 💥

Zmodyfikuj styl wykresu do postaci b+--. Jaki efekt został otrzymany? Przetestuj inne modyfikacje odnoszące się do linii, zawarte w dokumentacji biblioteki.


Aby wykres był pełnowartościowy, należy dodać etykiety na osiach X oraz Y. Służą do tego odpowiednio metody xlabel() oraz ylabel(). Jako argument przyjmują one tekst, który ma zostać wyświetlony na danej osi. Co więcej, możliwe jest wyświetlenie legendy, opisującej narysowane wykresy. Aby ją dodać, należy skorzystać z metody legend(). Trzeba przy tym pamiętać, że brak zdefiniowanych etykiet uniemożliwi dodanie legendy do wykresu. Aby przypisać etykietę do krzywej, konieczne jest ponowne rozszerzenie listy argumentów metody plot():

plot.plot(x, y, 'b+--', label='Wykres 1')

Możliwe jest ponadto dodanie tytułu przy pomocy metody title().


💥 Zadanie 4 💥

Zmodyfikuj położenie legendy w taki sposób, aby była ona widoczna w prawym dolnym rogu wykresu [3].


Wykres wygląda już zdecydowanie lepiej, jednak jego czytelność pozostaje w dalszym ciągu ograniczona z uwagi na brak siatek pomocniczych i nieodpowiednie formatowanie zakresów osi. Rysowanie siatek można włączyć przy pomocy metody grid(). Możliwe jest tutaj pełne dopasowanie jej do potrzeb projektowanego wykresu [4].

plot.grid(linewidth=0.5)

Formatowanie osi można wykonać używając metod xlim() oraz ylim(). Jako argument przyjmują one listę wartości (minimalną oraz maksymalną).

plot.xlim([0, 5])
plot.ylim([0, 5])

Często używaną metodą jest także tight_layout(), która pozwala na dopasowanie przestrzeni wokół wykresu do aktualnie prezentowanych danych. W przypadku stosowania etykiet osi lub tytułu obejmujących kilka linii, metoda ta jest niezbędna, aby prawidłowo je wyświetlić.


💥 Zadanie 5 💥

Przygotuj wykres dla funkcji sin. Zbiór wartości dla osi X powinien zostać wygenerowany w oparciu o np.arange(0, 1, 0.01). Krzywa powinna być wykropkowana, koloru zielonego. Osie powinny zostać odpowiednio opisane. Wykres powinien zostać opatrzony tytułem. Legenda powinna znajdować się w lewym dolnym rogu. Siatka główna oraz pomocnicza powinny zostać włączone (grubość linii odpowiednio 0.5 oraz 0.25). Podpowiedź: przydatna może się okazać metoda minorticks_on().


Zapis wykresu do pliku

Niekiedy zdarza się, że zamiast natychmiastowej wizualizacji danych, pojawia się potrzeba zapisania jej do pliku. Matplotlib oferuje taką możliwość. Aby tego dokonać należy zamienić metodę show() na savefig(), a jako argument podać nazwę pliku wraz z rozszerzeniem.

import numpy as np
import matplotlib.pyplot as plot

x = np.arange(1, 100, 2)
y = x + 10

plot.plot(x, y)
plot.savefig('diagram.png')

Jednoczesna wizualizacja różnych danych

Matplotlib pozwala na prezentację wielu różnych danych w tym samych czasie. Można to zrobić na kilka sposobów. Pierwszym z nich jest narysowanie zbioru punktów na istniejącym już wykresie. Aby tego dokonać, wystarczy kilkukrotnie wywołać metodę plot() z nowymi współrzędnymi punktów.

Możliwe jest także narysowanie linii pionowej lub poziomej korzystając odpowiednio z metod hlines() [5] oraz vlines() [6].


💥 Zadanie 6 💥

Zmodyfikuj wykres dla funkcji sinus w taki sposób, aby widoczne były jednocześnie przebiegi dla funkcji sinus, cosinus oraz tangens. Zmienić należy zakresy osi oraz dodać linie poziomą oraz pionową, przechodzące przez środek układu współrzędnych.


Drugi sposób to wywołanie kilku niezależnych okien, w których wizualizowane będą pojedyncze wykresy. Aby oddzielić dane od siebie, należy skorzystać z metody figure(). Jako argument przyjmuje ona m.in. nazwę nowego okna. Ta powinna być unikalna. Zaznaczyć trzeba, że metoda ta musi poprzedzać wywołanie metod(y) plot(). Uwaga: Formatowanie wykresu należy zastosować dla każdego okna niezależnie.


💥 Zadanie 7 💥

Zmodyfikuj wykres z poprzedniego zadania w taki sposób, aby przebieg każdej funkcji trygonometrycznej został wyświetlony w osobnym oknie. Pamiętaj o prawidłowym sformatowaniu każdego z wykresów.


Trzeci sposób to prezentacja danych w pojedynczym oknie, ale w ramach odrębnych wykresów. Służy do tego metoda subplots(). Jako argumenty może ona przyjąć liczbę wierszy, liczbę kolumn oraz rozmiar powstałego okna. Zwracane są dwa uchwyty, pozwalające na zarządzanie pojedynczymi wykresami (axis) oraz samym oknem (figure). Zakres materiału realizowanego na zajęciach nie będzie obejmował zarządzania siatką wykresów, pozwalającą na stosowanie układów niestandardowych [7].

figure, axis = plot.subplots(1, 2)
figure, axis = plot.subplots(2, 2, figsize=(14,7))

Przykładowy kod, ilustrujący utworzenie dwóch wykresów w ramach pojedynczego okna, został załączony poniżej.

figure, axis = plot.subplots(1, 2, figsize=(14,7))

x_a = [0, 5]
y_a = [0, 5]

x_b = np.arange(1, 100, 1)
y_b = x_b + 10

axis[0].plot(x_a, y_a, 'r')
axis[1].plot(x_b, y_b, 'g')

plot.show()

💥 Zadanie 8 💥

Przetestuj i przeanalizuj działanie powyższego kodu.


Zmiana wyglądu wykresu może zostać dokonana przy użyciu standardowych metod, poprzedzonych prefiksem set_ (np. set_ylabel(), set_xlim(), set_title()).

axis[0].set_ylabel('Os Y')

💥 Zadanie 9 💥

Sformatuj wykresy, dodając etykiety osi, tytuły oraz legendę.


Zadania

  1. Utwórz okno zawierające 4 wykresy (2 x 2). Wykresy powinny wizualizować kolejno:
    • przebiegi dla funkcji trygonometrycznych sin oraz cos;
    • wykres hiperboli;
    • wykres paraboli;
    • wykres dla danych, wygenerowanych przy użyciu numpy.random.
  2. Każdy z wykresów opatrz odpowiednim tytułem oraz opisz jego osie.
  3. Dodaj siatki pomocnicze. Linie główne powinny być grubsze, niż pomocnicze. Linie pomocnicze powinny być przerywane.
  4. Dodaj legendy i umieść je w zewnętrznych narożnikach wykresów.
  5. Zmodyfikuj wykresy w taki sposób, aby każda krzywa miała unikalny styl.

Referencje

  1. https://matplotlib.org/
  2. https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html
  3. https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.legend.html
  4. https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.grid.html
  5. https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.hlines.html
  6. https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.vlines.html
  7. https://matplotlib.org/stable/api/gridspec_api.html